package com.jzo2o.common.utils;

import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.Function;

/**
 * 原始比较器无法处理空值问题，特写此工具类，提供支持空值排序的比较器
 */
public class ComparatorUtils {


    /**
     * 构建比较器，将空值元素（或元素的提取字段为空）排在头部
     *
     * @param keyExtractor 从元素中提取比较关键字的函数式接口
     * @param <T>          元素类型
     * @param <U>          提取的比较关键字类型（需实现Comparable接口）
     * @return 支持空值排头部的比较器
     */
    public static <T, U extends Comparable<? super U>> Comparator<T> nullToFirstComparing(Function<? super T, ? extends U> keyExtractor) {
        return nullComparing(true, keyExtractor);
    }

    /**
     * 构建比较器，将空值元素（或元素的提取字段为空）排在尾部
     *
     * @param keyExtractor 从元素中提取比较关键字的函数式接口
     * @param <T>          元素类型
     * @param <U>          提取的比较关键字类型（需实现Comparable接口）
     * @return 支持空值排尾部的比较器
     */
    public static <T, U extends Comparable<? super U>> Comparator<T> nullToLastComparing(Function<? super T, ? extends U> keyExtractor) {
        return nullComparing(false, keyExtractor);
    }

    /**
     * 构建比较器，可自定义空值元素（或元素的提取字段为空）的排序位置（头部/尾部）
     *
     * @param nullFirst    空元素是否排到头部（true-头部，false-尾部）
     * @param keyExtractor 从元素中提取比较关键字的函数式接口
     * @param <T>          元素类型
     * @param <U>          提取的比较关键字类型（需实现Comparable接口）
     * @return 支持空值排序的比较器
     */
    public static <T, U extends Comparable<? super U>> Comparator<T> nullComparing(boolean nullFirst,
                                                                                   Function<? super T, ? extends U> keyExtractor) {

        // 校验keyExtractor不为空
        Objects.requireNonNull(keyExtractor);
        // 返回匿名比较器实现，同时实现Serializable接口支持序列化
        return (Comparator<T> & Serializable)
                (c1, c2) -> {
                    // 判断元素c1或其提取字段是否为空
                    boolean c1NUll = ObjectUtils.isNull(c1) || ObjectUtils.isNull(keyExtractor.apply(c1));
                    // 判断元素c2或其提取字段是否为空
                    boolean c2NUll = ObjectUtils.isNull(c2) || ObjectUtils.isNull(keyExtractor.apply(c2));

                    // 若c1为空：c2也为空则返回0（相等）；否则根据nullFirst返回-1（排前）或1（排后）
                    if (c1NUll) {
                        return c2NUll ? 0 : (nullFirst ? -1 : 1);
                    }
                    // 若c2为空：根据nullFirst返回1（c1排后）或-1（c1排前）
                    else if (c2NUll) {
                        return nullFirst ? 1 : -1;
                    }
                    // 两者都不为空：使用提取的关键字进行自然排序
                    return keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
                };
    }

    /**
     * 判断比较器是否为正序（未反转）
     * 注：通过判断比较器类名是否包含"ReverseComparator"（默认反转比较器的类名标识）实现
     *
     * @param comparator 待判断的比较器
     * @return true-正序，false-倒序
     */
    public static boolean isAsc(Comparator<?> comparator) {
        // 校验comparator不为空
        Objects.requireNonNull(comparator);
        // 类名不包含"ReverseComparator"则视为正序
        return !comparator.getClass().getName().contains("ReverseComparator");
    }
}
